package cn.com.netedge.iot.frontend.comm.nio;

import cn.com.netedge.iot.frontend.comm.config.FeCommConfig;
import cn.com.netedge.iot.frontend.comm.constants.ChannelConstant;
import cn.com.netedge.iot.frontend.comm.utils.JmsMsgUtil;
import com.alibaba.fastjson2.JSON;
import cn.com.netedge.iot.common.constants.CacheKeyConstants;
import cn.com.netedge.iot.common.constants.MqConstants;
import cn.com.netedge.iot.common.dataobject.DeviceInfo;
import cn.com.netedge.iot.common.enums.OnlineStatusEnum;
import cn.com.netedge.iot.common.utils.DateUtil;
import cn.com.netedge.iot.common.utils.RedisUtil;
import cn.com.netedge.iot.common.utils.StringUtil;
import cn.com.netedge.iot.frontend.comm.utils.FeCommCacheUtil;
import cn.com.netedge.iot.common.dataobject.DeviceRunningInfo;
import cn.com.netedge.iot.model.online.DataCOnlineModel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

public class FeChannelHandler extends ChannelInboundHandlerAdapter {
    private static Logger logger = LoggerFactory.getLogger(FeChannelHandler.class);
    private static final int OFFLINE = 0;

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        //增加通道信息
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        Channel channel = ctx.channel();
        ChannelConstant.CHANNEL_MAP.put(channelId, channel);
        long now = System.currentTimeMillis();
        ChannelConstant.CHANNEL_CREATE_TIME_MAP.put(channelId, now);
        logger.info("id:{} channel is added.", channelId);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
        Channel channel = ctx.channel();
        removeChannel(channel);

        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel is removed.", channelId);
    }

    private String getChannelId(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        if (channel == null) {
            logger.warn("channel is null");
            return "";
        }
        ChannelId id = channel.id();
        if (id == null) {
            logger.warn("channelId is null");
            return "";
        }
        return id.asLongText();
    }

    private void removeChannel(Channel channel) {
        //删除通道信息
        ChannelId id = channel.id();
        ChannelConstant.CHANNEL_MAP.remove(id.asLongText());
        ChannelConstant.CHANNEL_CREATE_TIME_MAP.remove(id.asLongText());

        String key = CacheKeyConstants.KEY_CHANNEL + id.asLongText();
        //查找终端地址
        String deviceInfoJson = RedisUtil.get(key);
        //更新缓存中通道-终端对应信息
        RedisUtil.delete(key);
        logger.info("key:{} channelInfo is deleted from redis .", key);
        if (StringUtil.isEmpty(deviceInfoJson)) {
            logger.warn("{} 's cache content is null", key);
            return;
        }
        DeviceInfo deviceInfo = JSON.parseObject(deviceInfoJson, DeviceInfo.class);
        if (deviceInfo == null) {
            logger.warn("{} convert to rtuinfo failed", deviceInfoJson);
            return;
        }
        String deviceNumber = deviceInfo.getDeviceNumber();
        int deviceType = deviceInfo.getDeviceType();
        if (StringUtil.isEmpty(deviceNumber)) {
            logger.warn("rtuinfo: {} , rtu's commaddress is null", deviceInfoJson);
            return;
        }
        String path = FeCommConfig.getMachineName() + "/" + deviceNumber + "/" + deviceType;
        FeCommCacheUtil.delKey(path);
        logger.info("path:{} channel is deleted. ", path);

        //保证终端串行执行
        ChannelConstant.SEND_FLAG_MAP.put(deviceNumber + "_" + deviceType, 0L);

        //更新终端运行信息
        key = CacheKeyConstants.KEY_DEVICE_RUNNING + deviceNumber + "_" + deviceType;
        String deviceRunningInfoJson = RedisUtil.get(key);
        if (StringUtil.isEmpty(deviceRunningInfoJson)) {
            logger.warn("runCurInfo: {} , device's running info is null", deviceRunningInfoJson);
            return;
        }
        DeviceRunningInfo deviceRunningInfo = JSON.parseObject(deviceRunningInfoJson, DeviceRunningInfo.class);
        if (deviceRunningInfo == null) {
            logger.warn("json: {} , convert to DeviceRunningInfo failed", deviceRunningInfoJson);
            return;
        }
        int statusCode = OnlineStatusEnum.OFFLINE.getCode();
        deviceRunningInfo.setCurStatus(statusCode);
        deviceRunningInfo.setMachineName(null);
        String json = JSON.toJSONString(deviceRunningInfo);
        FeCommCacheUtil.setString(key, json);

        DataCOnlineModel dataCOnlineModel = new DataCOnlineModel();
        dataCOnlineModel.setDeviceId(deviceInfo.getDeviceId());
        dataCOnlineModel.setDeviceType(deviceInfo.getDeviceType());
        dataCOnlineModel.setIsOnline(OFFLINE);
        Date now = new Date();
        dataCOnlineModel.setOccurTime(DateUtil.DateToLongStr(now));
        JmsMsgUtil.sendMessage(MqConstants.QUEUE_DATA_C_ONLINE_MESSAGE, JSON.toJSONString(dataCOnlineModel));
        logger.info("key:{} rtu status is updated deleted from redis .", key, json);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel is actived.", channelId);
        int count = ChannelConstant.CHANNEL_COUNT.incrementAndGet();
        logger.info("channel count:" + count);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        logger.debug("channel inactive");
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel is inactive.", channelId);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        int count = ChannelConstant.CHANNEL_COUNT.decrementAndGet();
        logger.info("channel count:" + count);
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel is registered.", channelId);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel is unregistered.", channelId);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        int count = ChannelConstant.CHANNEL_COUNT.decrementAndGet();
        logger.info("channel count:" + count);
        Channel channel = ctx.channel();
        if (channel.isActive()) {
            ctx.close();
        }

        removeChannel(channel);
        String channelId = getChannelId(ctx);
        if (StringUtil.isEmpty(channelId)) {
            return;
        }
        logger.info("id:{} channel throws exception. Exception:", channelId, cause);
    }
}
